/**  
*  Doku2Buddy - A DokuWiki to BuddyPress Wiki-Component Converter
*  Copyright (C) 2010 Skye Book
*  
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*  
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*  
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.sbook.d2b.formatting;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;


/**
 * @author Skye Book
 *
 */
public class DokuInterpreter {
	private File articleFolder;
	private File metaFolder;
	private ArrayList<File> fileList;
	private ArrayList<File> metaFolders;
	private ArrayList<String> authors;
	
	private URL verifiedURL = null;
	
	private ArrayList<DokuArticle> articles;

	/**
	 * @param dokuFilepath Local location of the DokuWiki installation.
	 * @param dokuURL Accessible, either locally or remotely, URL of the DokuWiki installation.
	 */
	public DokuInterpreter(File dokuFilepath, String dokuURL){
		try {
			authors = new ArrayList<String>();
			verifyURL(dokuURL);
			if(verifiedURL==null){
				System.err.println("verifiedURL is null and it shouldn't be");
			}
			
			articleFolder = new File(new URL(dokuFilepath.toURI().toURL()+"/data/pages/").toURI());
			metaFolder = new File(new URL(dokuFilepath.toURI().toURL()+"/data/meta/").toURI());
			
			metaFolders = new ArrayList<File>();
			collectMetaFolders(metaFolder);
			
			// Count the files
			fileList = new ArrayList<File>();
			countPages(articleFolder);
			
			System.out.println(fileList.size() + " Articles listed");
			listFiles(null);
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
	
	private void countPages(File folder){
		File[] files = folder.listFiles();
		for(int i=0; i<files.length; i++){
			File thisFile = files[i];
			if(thisFile.isFile()){
				// ignore uninteresting files like DS_Store (can you tell I debugged this on a Mac?!)
				if(thisFile.getName().endsWith(".txt")){
					fileList.add(thisFile);
				}
			}
			else if(thisFile.isDirectory()){
				countPages(thisFile);
			}
		}
	}
	
	/**
	 * Lists the files found by the interpreter.
	 */
	public void listFiles(File outputFile){
		if(outputFile==null){
			// write to console
		}
		else{
			
		}
		articles = new ArrayList<DokuArticle>();
		Iterator<File> it = fileList.iterator();
		while(it.hasNext()){
			DokuArticle article = new DokuArticle();
			File file = it.next();
			String filename = getFileName(file);
			analyzeChangesFile(filename, article);
			readArticleBody(file, article);
			readRawArticle(file, article);
			articles.add(article);
			System.out.println(article.getTitle() + " By " + article.getAuthor());
		}
	}
	
	private String getFileName(File file){
		try {
			return file.toURI().toURL().toString().substring(
					file.toURI().toURL().toString().lastIndexOf("/")+1,
					file.toURI().toURL().toString().length());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private void collectMetaFolders(File directory){
		File[] metaFiles = directory.listFiles();
		for(int i=0; i<metaFiles.length; i++){
			File thisFile = metaFiles[i];
			if(thisFile.isDirectory()){
				metaFolders.add(thisFile);
				collectMetaFolders(thisFile);
			}
		}
	}
	
	private void analyzeChangesFile(String articleName, DokuArticle article){
		try {
			String extensionLessArticleName = articleName.substring(0, articleName.lastIndexOf("."));
			article.setTitle(extensionLessArticleName);
			File changesFile = new File(new URL(metaFolder.toURI().toURL()+"/"+extensionLessArticleName+".changes").toURI());
			if(!changesFile.exists()){
				Iterator<File> moreFolders = metaFolders.iterator();
				while(moreFolders.hasNext()){
					changesFile = new File(new URL(moreFolders.next().toURI().toURL()+"/"+extensionLessArticleName+".changes").toURI());
					if(changesFile.exists()){
						break;
					}
				}
			}
			
			// see if any of the other folders had the changes file
			if(!changesFile.exists()){
				System.out.println("Changes file not found for " + articleName);
			}
			else{
				FileInputStream inStream = new FileInputStream(changesFile);
				BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream(inStream)));
				String currentLine;
				String lastLine = null;
				while((currentLine = reader.readLine())!=null){
					lastLine=currentLine;
				}
				article.setDate(findDate(lastLine));
				article.setAuthor(findAuthor(lastLine, extensionLessArticleName));
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private String findAuthor(String lastLine, String extensionLessArticleName){
		
		String cut = lastLine.substring(lastLine.lastIndexOf(extensionLessArticleName)+extensionLessArticleName.length());
		cut = cut.trim();
		
		String author;
		/* Doku inserts a tab after the author if there is a comment
		 * with the edit (otherwise, the author is the last element on the line)
		 */
		if(cut.contains("\t")){
			author = cut.substring(0, cut.indexOf("\t"));
		}
		else{
			author = cut;
		}
		checkOrAddAuthor(author);
		return author;
	}
	
	private long findDate(String lastLine){
		String dateString = lastLine.substring(0, 10);
		return Long.parseLong(dateString);
	}
	
	private boolean verifyURL(String rawURL){
		try {
			verifiedURL = new URL(rawURL);
			return true;
		} catch (MalformedURLException e) {
			if(e.getMessage().startsWith("no protocol")){
				verifyURL("http://"+rawURL);
				return true;
			}
			else{
				System.out.println("BAD URL!");
				e.printStackTrace();
				System.exit(0);
			}
		}
		return false;
	}
	
	private void readArticleBody(File articleFile, Article article){
		String relativeArticle = articleFile.toString().substring(articleFolder.toString().length()+1, articleFile.toString().length());
		relativeArticle = relativeArticle.replaceAll("/", ":");
		relativeArticle = relativeArticle.substring(0, relativeArticle.lastIndexOf("."));
		try {
			URL finalURL = new URL(verifiedURL.toString()+"/doku.php/"+relativeArticle+"?do=export_xhtmlbody");
			DataInputStream dis = new DataInputStream(finalURL.openStream());
			BufferedReader pageReader = new BufferedReader(new InputStreamReader(dis));
			String entireFile="";
			String currentLine;
			while((currentLine=pageReader.readLine()) != null){
				entireFile += currentLine;
			}
			article.setMarkup(entireFile);
		} catch (MalformedURLException e) {
			// This shouldn't be happening at this point in time
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void readRawArticle(File localArticle, DokuArticle article){
		try {
			URL finalURL = localArticle.toURI().toURL();
			DataInputStream dis = new DataInputStream(finalURL.openStream());
			BufferedReader pageReader = new BufferedReader(new InputStreamReader(dis));
			String entireFile="";
			String currentLine;
			while((currentLine=pageReader.readLine()) != null){
				entireFile += currentLine+="\n";
			}
			article.setOriginalMarkup(entireFile);
		} catch (MalformedURLException e) {
			// This shouldn't be happening at this point in time
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	// Checks if the author has already been added to the list and adds the name if not.
	private void checkOrAddAuthor(String author){
		Iterator<String> it = authors.iterator();
		while(it.hasNext()){
			if(it.next().equals(author)){
				return;
			}
		}
		authors.add(author);
	}

	/**
	 * @return the articles
	 */
	public ArrayList<DokuArticle> getArticles() {
		return articles;
	}

	public ArrayList<String> getAuthors() {
		return authors;
	}
}